java同步器AQS架构如何释放锁和同步队列 您所在的位置:网站首页 locksupport 使用 java同步器AQS架构如何释放锁和同步队列

java同步器AQS架构如何释放锁和同步队列

2023-05-13 17:25| 来源: 网络整理| 查看: 265

引导语

AQS 的内容太多,所以我们分成了两个章节,没有看过 AQS 上半章节的同学可以回首看一下哈,上半章节里面说了很多锁的基本概念,基本属性,如何获得锁等等,本章我们主要聊下如何释放锁和同步队列两大部分。

1、释放锁

释放锁的触发时机就是我们常用的 Lock.unLock () 方法,目的就是让线程释放对资源的访问权(流程见整体架构图紫色路线)。

释放锁也是分为两类,一类是排它锁的释放,一类是共享锁的释放,我们分别来看下。

1.1、释放排它锁 release

排它锁的释放就比较简单了,从队头开始,找它的下一个节点,如果下一个节点是空的,就会从尾开始,一直找到状态不是取消的节点,然后释放该节点,源码如下:

// unlock 的基础方法 public final boolean release(int arg) { // tryRelease 交给实现类去实现,一般就是用当前同步器状态减去 arg,如果返回 true 说明成功释放锁。 if (tryRelease(arg)) { Node h = head; // 头节点不为空,并且非初始化状态 if (h != null && h.waitStatus != 0) // 从头开始唤醒等待锁的节点 unparkSuccessor(h); return true; } return false; } // 很有意思的方法,当线程释放锁成功后,从 node 开始唤醒同步队列中的节点 // 通过唤醒机制,保证线程不会一直在同步队列中阻塞等待 private void unparkSuccessor(Node node) { // node 节点是当前释放锁的节点,也是同步队列的头节点 int ws = node.waitStatus; // 如果节点已经被取消了,把节点的状态置为初始化 if (ws < 0) compareAndSetWaitStatus(node, ws, 0); // 拿出 node 节点的后面一个节点 Node s = node.next; // s 为空,表示 node 的后一个节点为空 // s.waitStatus 大于0,代表 s 节点已经被取消了 // 遇到以上这两种情况,就从队尾开始,向前遍历,找到第一个 waitStatus 字段不是被取消的 if (s == null || s.waitStatus > 0) { s = null; // 这里从尾迭代,而不是从头开始迭代是有原因的。 // 主要是因为节点被阻塞的时候,是在 acquireQueued 方法里面被阻塞的,唤醒时也一定会在 acquireQueued 方法里面被唤醒,唤醒之后的条件是,判断当前节点的前置节点是否是头节点,这里是判断当前节点的前置节点,所以这里必须使用从尾到头的迭代顺序才行,目的就是为了过滤掉无效的前置节点,不然节点被唤醒时,发现其前置节点还是无效节点,就又会陷入阻塞。 for (Node t = tail; t != null && t != node; t = t.prev) // t.waitStatus


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有